home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / upc12bs1.zip / MAIL / deliver.c < prev    next >
C/C++ Source or Header  |  1993-09-23  |  41KB  |  1,054 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    d e l i v e r  . c                                              */
  3. /*                                                                    */
  4. /*    UUPC/extended mail delivery subroutines                         */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989-1993 by Kendra Electronic            */
  9. /*    Wonderworks.                                                    */
  10. /*                                                                    */
  11. /*    All rights reserved except those explicitly granted by the      */
  12. /*    UUPC/extended license agreement.                                */
  13. /*--------------------------------------------------------------------*/
  14.  
  15. /*--------------------------------------------------------------------*/
  16. /*                          RCS Information                           */
  17. /*--------------------------------------------------------------------*/
  18.  
  19. /*
  20.  *    $Id: deliver.c 1.16 1993/09/23 03:26:51 ahd Exp $
  21.  *
  22.  *    $Log: deliver.c $
  23.  * Revision 1.16  1993/09/23  03:26:51  ahd
  24.  * Alter bounce message for "no path to host" error
  25.  *
  26.  * Revision 1.15  1993/09/20  04:41:54  ahd
  27.  * OS/2 2.x support
  28.  *
  29.  * Revision 1.14  1993/08/02  03:24:59  ahd
  30.  * Further changes in support of Robert Denny's Windows 3.x support
  31.  *
  32.  * Revision 1.13  1993/07/31  16:26:01  ahd
  33.  * Changes in support of Robert Denny's Windows support
  34.  *
  35.  * Revision 1.12  1993/06/21  02:17:31  ahd
  36.  * Correct errors in mail routing via HOSTPATH
  37.  *
  38.  * Revision 1.11  1993/06/13  14:06:00  ahd
  39.  * Save invoked program name and use it for recursive calls
  40.  * Loosen up bounced mail copy loop to avoid NT crashes
  41.  *
  42.  * Revision 1.10  1993/05/30  00:01:47  ahd
  43.  * Expand path of system alias files to allow userid references
  44.  *
  45.  * Revision 1.9  1993/05/06  03:41:48  ahd
  46.  * Don't rebounce mail to the postmaster
  47.  * Change directories as needed to provide reasonable default drives
  48.  * Do not use possibly invalid home directory to push directory on
  49.  * system aliases
  50.  *
  51.  * Revision 1.8  1993/05/03  02:41:57  ahd
  52.  * Make deliver not rebounce mail to the postmonstor
  53.  *
  54.  * Revision 1.7  1993/04/16  12:55:36  dmwatt
  55.  * Windows/NT sound support
  56.  *
  57.  * Revision 1.6  1993/04/15  03:17:21  ahd
  58.  * Basic bounce support
  59.  *
  60.  * Revision 1.5  1993/04/11  00:33:05  ahd
  61.  * Global edits for year, TEXT, etc.
  62.  *
  63.  * Revision 1.4  1992/12/18  13:05:18  ahd
  64.  * Use one token on request line for UUCP
  65.  *
  66.  * Revision 1.3  1992/12/05  23:38:43  ahd
  67.  * Skip blanks as well as unprintable characters
  68.  *
  69.  * Revision 1.2  1992/12/04  01:00:27  ahd
  70.  * Add system alias support
  71.  *
  72.  */
  73.  
  74. /*--------------------------------------------------------------------*/
  75. /*    Embedded Japanese support provided by Kenji Rikitake            */
  76. /*    28-AUG-1991                                                     */
  77. /*                                                                    */
  78. /*    On Japanese support:                                            */
  79. /*                                                                    */
  80. /*    Japanese MS-DOS uses a 2byte Kanji (Japanese ideogram) code     */
  81. /*    called "Shift-JIS".  This cannot be delivered via SMTP since    */
  82. /*    Shift-JIS maps its first byte from 0x80-0x9f and 0xe0-0xfc.     */
  83. /*    JUNET requests all hosts to send Kanji in a 7bit subset of      */
  84. /*    ISO2022.  This is commonly called "JIS 7bit".                   */
  85. /*                                                                    */
  86. /*    To provide Japanese functionality, you need to convert all      */
  87. /*    remote delivery messages to JIS 7bit, and all local delivery    */
  88. /*    messages to Shift-JIS.                                          */
  89. /*--------------------------------------------------------------------*/
  90.  
  91. #define INCLUDE ":include:"
  92.  
  93. /*--------------------------------------------------------------------*/
  94. /*                        System include files                        */
  95. /*--------------------------------------------------------------------*/
  96.  
  97. #include <stdio.h>
  98. #include <stdlib.h>
  99. #include <io.h>
  100. #include <ctype.h>
  101. #include <sys/types.h>
  102. #include <string.h>
  103. #include <process.h>
  104. #include <limits.h>
  105.  
  106. /*--------------------------------------------------------------------*/
  107. /*                    UUPC/extended include files                     */
  108. /*--------------------------------------------------------------------*/
  109.  
  110. #include "lib.h"
  111. #include "address.h"
  112. #include "deliver.h"
  113. #include "expath.h"
  114. #include "execute.h"
  115. #include "getseq.h"
  116. #include "kanjicnv.h"
  117. #include "hlib.h"
  118. #include "hostable.h"
  119. #include "import.h"
  120. #include "pushpop.h"
  121. #include "security.h"
  122. #include "stater.h"
  123. #include "usertabl.h"
  124. #include "sysalias.h"
  125. #include "timestmp.h"
  126. #include "trumpet.h"
  127.  
  128. /*--------------------------------------------------------------------*/
  129. /*        Define current file name for panic() and printerr()         */
  130. /*--------------------------------------------------------------------*/
  131.  
  132. currentfile();
  133.  
  134. /*--------------------------------------------------------------------*/
  135. /*                        Internal prototypes                         */
  136. /*--------------------------------------------------------------------*/
  137.  
  138. static size_t DeliverLocal( const char *input,  /* Input file name    */
  139.                           char *user,     /* Target address           */
  140.                           const boolean sysalias,
  141.                                              /* Already sys alias     */
  142.                           boolean validate); /* Validate/forward
  143.                                                 local mail            */
  144.  
  145. static int DeliverFile( const char *input,
  146.                         const char *mboxname,
  147.                         const long start,
  148.                         const long end,
  149.                         boolean *announce,
  150.                         struct UserTable *userp,
  151.                         const boolean sysalias,  /* Already sys alias     */
  152.                         const boolean validate,
  153.                         const char *user );
  154.  
  155. static size_t DeliverRemote( const char *input, /* Input file name    */
  156.                              const char *address,  /* Target address  */
  157.                              const char *path);
  158.  
  159. static size_t DeliverGateway(   const char *input,
  160.                                 const char *user,
  161.                                 const char *node,
  162.                                 const struct HostTable *hostp,
  163.                                 const boolean validate );
  164.  
  165. static int CopyData(   const boolean remotedelivery,
  166.                        const char *input,
  167.                        FILE *mbox);
  168.  
  169. static char *stats( const char *fname );
  170.  
  171. size_t Bounce( const char *input,
  172.                const char *text,
  173.                const char *data,
  174.                const char *address,
  175.                const boolean validate );
  176.  
  177. /*--------------------------------------------------------------------*/
  178. /*   Global (set by rmail.c) for number of hops this mail has seen    */
  179. /*--------------------------------------------------------------------*/
  180.  
  181.  KEWSHORT hops = 0;
  182.  
  183.  boolean remoteMail = FALSE;
  184.  
  185.  char *ruser = NULL;
  186.  char *rnode = NULL;
  187.  char *uuser = NULL;
  188.  
  189. /*--------------------------------------------------------------------*/
  190. /*    D e l i v e r                                                   */
  191. /*                                                                    */
  192. /*    Deliver mail to one user                                        */
  193. /*--------------------------------------------------------------------*/
  194.  
  195. size_t Deliver(       const char *input,    /* Input file name       */
  196.                             char *address,  /* Target address           */
  197.                       const boolean sysalias,  /* Already sys alias     */
  198.                           boolean validate)  /* Validate/forward
  199.                                                 local mail            */
  200. {
  201.    char node[MAXADDR];
  202.    char path[MAXADDR];
  203.    char user[MAXADDR];
  204.    char *token;
  205.    struct HostTable *hostp;
  206.  
  207.    if ( strlen( address ) >= MAXADDR )
  208.       return Bounce( input,
  209.                      "Excessive address length",
  210.                      address,
  211.                      address,
  212.                      validate );
  213.  
  214.    user_at_node(address, path, node, user);
  215.  
  216. /*--------------------------------------------------------------------*/
  217. /*                       Handle local delivery                        */
  218. /*--------------------------------------------------------------------*/
  219.  
  220.    if (equal(path, E_nodename)) /* Local node?                       */
  221.    {
  222.       struct HostTable *hostx = checkname( node );
  223.       if (hostx->hstatus == localhost)  /* Really the local node?    */
  224.          return DeliverLocal( input, user, sysalias, validate );
  225.                                  /* Yes!                             */
  226.       else
  227.          return Bounce( input,
  228.                  "No known delivery path for host",
  229.                   address,
  230.                   address,
  231.                   validate );
  232.    }  /* if */
  233.  
  234. /*--------------------------------------------------------------------*/
  235. /*                    Do we need loop protection?                     */
  236. /*--------------------------------------------------------------------*/
  237.  
  238.    if (hops > E_maxhops)
  239.       return Bounce(input,
  240.              "Excessive number of hops",
  241.              address,
  242.              address,
  243.              validate );
  244.  
  245. /*--------------------------------------------------------------------*/
  246. /*                   Deliver to a gateway if needed                   */
  247. /*--------------------------------------------------------------------*/
  248.  
  249.    hostp = checkname( path );
  250.    if ( (hostp != BADHOST) && (hostp->hstatus == gatewayed))
  251.       return DeliverGateway( input, user, node, hostp, validate );
  252.  
  253. /*--------------------------------------------------------------------*/
  254. /*         Deliver mail to a system directory connected to us         */
  255. /*--------------------------------------------------------------------*/
  256.  
  257.    if (equal(path,node))   /* Directly connected system?          */
  258.       return DeliverRemote( input, user, path); /* Yes            */
  259.  
  260. /*--------------------------------------------------------------------*/
  261. /*   Default delivery; strip any this node and the directly           */
  262. /*   connected system from the address, then deliver to the next      */
  263. /*   hop on the route                                                 */
  264. /*--------------------------------------------------------------------*/
  265.  
  266.    strcpy(node,address);
  267.    token = strtok(node,"!");  /* Get first host in path        */
  268.    if (equal( HostAlias(token), E_nodename)) /* Local system?  */
  269.    {
  270.       token =  strtok(NULL,"");  /* Yes --> Get rest of addr   */
  271.       strcpy(address, token);    /* Use it for address         */
  272.       token = strtok(token,"!"); /* Get next host in path      */
  273.    } /* if */
  274.  
  275.    if (equal( HostAlias(token), path ))  /* Next system?       */
  276.    {
  277.       token =  strtok(NULL,"");  /* Yes --> Get rest of addr   */
  278.       strcpy(address, token);    /* Use it for address         */
  279.    } /* if */
  280.  
  281.    if (!strpbrk(address,"!@"))   /* Any host delimiters?       */
  282.    {                             /* No --> Check for % routing */
  283.       token = strrchr(address,'%'); /* Get last percent sign   */
  284.       if (token != NULL)
  285.          *token = '@';           /* Make it an RFC-822 address */
  286.       else
  287.          printmsg(0,"Deliver: Cannot find node in \"%s\"",
  288.                address);         /* That's odd, it should not  */
  289.                                  /* be a local address!        */
  290.    } /* if */
  291.  
  292.    return DeliverRemote( input, address, path );
  293.  
  294. } /* Deliver */
  295.  
  296. /*--------------------------------------------------------------------*/
  297. /*    D e l i v e r L o c a l                                         */
  298. /*                                                                    */
  299. /*    Handle local delivery, including optional forwarding            */
  300. /*--------------------------------------------------------------------*/
  301.  
  302. static size_t DeliverLocal( const char *input,
  303.                                           /* Input file name          */
  304.                           char *user,     /* Target address           */
  305.                           const boolean sysalias,
  306.                                           /* Already sys alias     */
  307.                           boolean validate)  /* TRUE = validate,
  308.                                                 forward user's mail   */
  309. {
  310.    char mboxname[FILENAME_MAX];
  311.    struct UserTable *userp = NULL;
  312.    ALIASTABLE *aliasp = NULL;
  313.    int delivered = 0;
  314.    boolean announce = FALSE;
  315.    FILE *mbox;
  316.  
  317. /*--------------------------------------------------------------------*/
  318. /*    If the parameter is the postmaster, use the configuration       */
  319. /*    defined value for the postmaster                                */
  320. /*--------------------------------------------------------------------*/
  321.  
  322.    if (equali(user, POSTMASTER))
  323.       user = E_postmaster;
  324.  
  325. /*--------------------------------------------------------------------*/
  326. /*             Validate user id and check for forwarding              */
  327. /*--------------------------------------------------------------------*/
  328.  
  329.    if (validate)
  330.    {
  331.       validate = strcmp( E_postmaster , user);
  332.                                  /* Don't loop delivering to postmast*/
  333.  
  334.       userp = checkuser(user);   /* Locate user id in host table     */
  335.  
  336. /*--------------------------------------------------------------------*/
  337. /*                     Process any system aliases                     */
  338. /*--------------------------------------------------------------------*/
  339.  
  340.       if ( ! sysalias )
  341.       {
  342.          aliasp = checkalias( user );  /* System alias?             */
  343.  
  344.          if ( aliasp != NULL )
  345.          {
  346.             delivered += DeliverFile( input,
  347.                                       SysAliases,
  348.                                       aliasp->start,
  349.                                       aliasp->end,
  350.                                       &announce ,
  351.                                       userp,
  352.                                       TRUE,
  353.                                       validate,
  354.                                       user );
  355.  
  356.             if ( announce && ( userp != BADUSER ) && remoteMail )
  357.                trumpet( userp->beep);  /* Yes --> Inform the user    */
  358.             return delivered;
  359.  
  360.          } /* if */
  361.       } /* if */
  362.  
  363. /*--------------------------------------------------------------------*/
  364. /*             No system alias, verify the user is valid              */
  365. /*--------------------------------------------------------------------*/
  366.  
  367.       if ( userp == BADUSER )    /* Invalid user id?                 */
  368.       {                          /* Yes --> Dump in trash bin        */
  369.          return Bounce( input,
  370.                         "Invalid local address (not defined in PASSWD or ALIASES)",
  371.                         user,
  372.                         user,
  373.                         validate );
  374.       } /* if */
  375.  
  376. /*--------------------------------------------------------------------*/
  377. /*               The user id validated; handle the mail               */
  378. /*--------------------------------------------------------------------*/
  379.  
  380.       mkfilename(mboxname, userp->homedir, DOTFORWARD);
  381.  
  382.       if (access( mboxname, 0 )) /* The .forward file exists?        */
  383.          announce = TRUE;        /* No --> Fall through              */
  384.       else {
  385.          delivered += DeliverFile( input,
  386.                                    mboxname,
  387.                                    0,
  388.                                    LONG_MAX,
  389.                                    &announce,
  390.                                    userp,
  391.                                    FALSE,
  392.                                    validate,
  393.                                    user );
  394.  
  395.          if (announce && remoteMail)   /* Did we deliver mail locally?        */
  396.             trumpet( userp->beep);     /* Yes --> Inform the user       */
  397.          return delivered;
  398.  
  399.       } /* if */
  400.  
  401.    } /* if (validate) */
  402.  
  403. /*--------------------------------------------------------------------*/
  404. /*       The user is valid (or not validated) and not forwarded       */
  405. /*--------------------------------------------------------------------*/
  406.  
  407.    if ((*user == '/') || (isalpha( *user ) && user[1] == ':'))
  408.                               /* Absolute path from recursive call?   */
  409.       strcpy(mboxname, user); /* Yes --> Use it as-is                 */
  410.    else
  411.       mkmailbox(mboxname, user);
  412.                               /* No --> Build normal name             */
  413.  
  414.    printmsg(1,"Delivering mail %sfrom %s%s%s to %s",
  415.                         stats( input ),
  416.                         ruser,
  417.                         remoteMail ? "@" : "",
  418.                         remoteMail ? rnode : "",
  419.                          user );
  420.  
  421.    if ( announce && remoteMail )
  422.       trumpet( userp->beep);  /* Local delivery, inform the user     */
  423.  
  424.    mbox = FOPEN( mboxname , "a",TEXT_MODE );
  425.    if (mbox == NULL )
  426.    {
  427.       printerr(mboxname);
  428.       printmsg(0,"Cannot open mailbox \"%s\" for output",
  429.                   mboxname);
  430.       panic();
  431.    }
  432.  
  433.    if (!isatty(fileno(mbox)))
  434.       fputs(MESSAGESEP,mbox); /* Write separator line                 */
  435.  
  436.    return CopyData( FALSE, input , mbox );
  437.  
  438. } /* DeliverLocal */
  439.  
  440. /*--------------------------------------------------------------------*/
  441. /*       D e l i v e r F i l e                                        */
  442. /*                                                                    */
  443. /*       Process a local or system aliases file                       */
  444. /*--------------------------------------------------------------------*/
  445.  
  446. static int DeliverFile( const char *input,
  447.                         const char *fwrdname,
  448.                         const long start,
  449.                         const long end,
  450.                         boolean *announce,
  451.                         struct UserTable *userp,
  452.                         const boolean sysalias,  /* Already sys alias     */
  453.                         const boolean validate,
  454.                         const char *user )
  455. {
  456.    char buf[BUFSIZ];
  457.    FILE *fwrd = FOPEN(fwrdname, "r",TEXT_MODE);
  458.    char *cwd = sysalias ? E_tempdir : userp->homedir;
  459.    int delivered = 0;
  460.  
  461.    if ( fwrd == NULL )
  462.    {
  463.       printerr( fwrdname );
  464.       return Bounce( input,
  465.                      "Cannot open forward file",
  466.                      fwrdname,
  467.                      user,
  468.                      validate );
  469.    }
  470.  
  471.    if ( start != 0 )
  472.       fseek( fwrd, start, SEEK_SET);
  473.  
  474.    while((ftell(fwrd) < end) && (fgets( buf, BUFSIZ, fwrd) != NULL ))
  475.    {
  476.       char *s = buf;
  477.       char c;
  478.       char *nextfile = NULL;
  479.  
  480.       if ( buf[ strlen(buf) - 1 ]== '\n')
  481.          buf[ strlen(buf) - 1 ] = '\0';
  482.  
  483.       while( *s && ! isgraph( *s ))    /* Trim leading white space      */
  484.          s++;
  485.  
  486.       printmsg(8,"Forwarding to \"%s\"", s);
  487.       if ( equalni( buf, INCLUDE, strlen(INCLUDE)))
  488.       {
  489.          nextfile = strtok( s + strlen(INCLUDE), WHITESPACE );
  490.          if ( nextfile == NULL )
  491.          {
  492.             return Bounce(input,
  493.                           "Missing forwarding file for alias",
  494.                           fwrdname,
  495.                           user,
  496.                           validate );
  497.          }
  498.          else
  499.             c = ':';
  500.       } /* if */
  501.       else if ( isalpha(*s ) && (s[1] == ':'))  /* Drive name?    */
  502.          c = '/';             /* Yes --> flag as absolute path    */
  503.       else if ( *s == ':')    /* Avoid false triggers ...         */
  504.          c = ' ';             /* ... by making it general case    */
  505.       else                    /* Handle other cases in switch ... */
  506.          c = *s;
  507.  
  508.       switch(c)
  509.       {
  510.          case '#':
  511.             break;            /* Comment, ignore            */
  512.  
  513.          case '\0':
  514.             break;            /* Empty line, ignore         */
  515.  
  516.          case '|':               /* Pipe mail into a command   */
  517.          {
  518.             long here = ftell(fwrd);
  519.  
  520.             fclose(fwrd);
  521.             PushDir( cwd );
  522.             printmsg(1,"Piping mail%s from %s@%s for %s into %s",
  523.                         stats( input ),
  524.                         ruser,
  525.                         rnode,
  526.                         user,
  527.                         s + 1 );
  528.  
  529.             executeCommand( s + 1, input, NULL, TRUE, FALSE );
  530.             PopDir();
  531.             delivered += 1;
  532.             fwrd = FOPEN(fwrdname, "r",TEXT_MODE);
  533.             fseek( fwrd, here, SEEK_SET);
  534.             break;
  535.          } /* case */
  536.  
  537.          case '\\':              /* Deliver without forwarding */
  538.             delivered += Deliver( input, &s[1], TRUE, FALSE );
  539.             *announce = TRUE;
  540.             break;
  541.  
  542.          case ':':
  543.          {
  544.             char fname[FILENAME_MAX];
  545.             strcpy( fname, nextfile);
  546.             expand_path(nextfile, NULL, cwd, E_mailext);
  547.             delivered += DeliverFile( input, nextfile, 0, LONG_MAX,
  548.                                       announce, userp,
  549.                                       FALSE, TRUE, user );
  550.             break;
  551.          }
  552.  
  553.          case '/':               /* Save in absolute path name */
  554.          case '~':
  555.             if (expand_path(s, NULL, cwd, E_mailext) == NULL )
  556.             {
  557.                return Bounce(input,
  558.                              "Invalid path in forwarding file name",
  559.                              s,
  560.                              user,
  561.                              validate );
  562.  
  563.             }
  564.             else
  565.                delivered += DeliverLocal( input, s, sysalias, FALSE );
  566.             *announce = TRUE;
  567.             break;
  568.  
  569.          default:                /* Deliver normally           */
  570.               delivered += Deliver( input, s, sysalias, validate );
  571.       } /* switch */
  572.    } /* while */
  573.  
  574.    fclose( fwrd );
  575.  
  576.    return delivered;
  577.  
  578. } /* DeliverFile */
  579.  
  580. /*--------------------------------------------------------------------*/
  581. /*    D e l i v e r G a t e w a y                                     */
  582. /*                                                                    */
  583. /*    Deliver mail via a gateway program                              */
  584. /*--------------------------------------------------------------------*/
  585.  
  586. static size_t DeliverGateway(   const char *input,
  587.                                 const char *user,
  588.                                 const char *node,
  589.                                 const struct HostTable *hostp,
  590.                                 const boolean validate )
  591. {
  592.    char command[BUFSIZ];
  593.    int rc;
  594.  
  595. /*--------------------------------------------------------------------*/
  596. /*    Format the command and tell the user what we're going to do     */
  597. /*--------------------------------------------------------------------*/
  598.  
  599.    sprintf(command , "%s %s %s %s",
  600.                      hostp->via,          /* Program to perform forward */
  601.                      hostp->hostname,     /* Nominal host routing via   */
  602.                      node ,               /* Final destination system   */
  603.                      user );              /* user on "node" for delivery*/
  604.  
  605.    printmsg(3,"DeliverGateway: %s", command);
  606.  
  607.    printmsg(1,
  608.       "Gatewaying mail %sfrom %s@%s to %s@%s via %s using \"%s\"",
  609.        stats( input ),
  610.        ruser, rnode, user, node, hostp->hostname, hostp->via);
  611.  
  612. /*--------------------------------------------------------------------*/
  613. /*  Run the command and return caller with count of mail delivered    */
  614. /*--------------------------------------------------------------------*/
  615.  
  616.    rc = executeCommand( command, input, NULL, TRUE, FALSE );
  617.  
  618.    if ( rc == 0 )
  619.       return 1;
  620.    else {
  621.       char who[MAXADDR];
  622.  
  623.       sprintf( who, "%s@%s", user, node );
  624.       return Bounce( input,
  625.                      "Gateway command returned non-zero exit status",
  626.                      command,
  627.                      who,
  628.                      validate );
  629.    } /* else */
  630.  
  631. } /* DeliveryGateway */
  632.  
  633. /*--------------------------------------------------------------------*/
  634. /*    D e l i v e r R e m o t e                                       */
  635. /*                                                                    */
  636. /*    Queue mail for delivery on another system via UUCP              */
  637. /*--------------------------------------------------------------------*/
  638.  
  639. static size_t DeliverRemote( const char *input, /* Input file name    */
  640.                     const char *address,  /* Target address           */
  641.                     const char *path)
  642. {
  643.    static char *spool_fmt = SPOOLFMT;              /* spool file name */
  644.    static char *dataf_fmt = DATAFFMT;
  645.    static char *send_cmd  = "S %s %s %s - %s 0666\n";
  646.    static long seqno = 0;
  647.    static char *SavePath = NULL;
  648.    FILE *stream;              /* For writing out data                */
  649.    static char everyone[500]; /* 512, with room for "rmail "         */
  650.  
  651.    char msfile[FILENAME_MAX]; /* MS-DOS format name of files         */
  652.    char msname[22];           /* MS-DOS format w/o path name         */
  653.  
  654.    char tmfile[15];           /* Call file, UNIX format name         */
  655.    static char ixfile[15];    /* eXecute file for remote system,
  656.                                 UNIX format name for local system   */
  657.    static char idfile[15];    /* Data file, UNIX format name         */
  658.    static char rdfile[15];    /* Data file name on remote system,
  659.                                  UNIX format                         */
  660.    static char rxfile[15];    /* Remote system UNIX name of eXecute
  661.                                  file                                */
  662.  
  663.    printmsg(1,"Spooling mail %sfrom %s%s%s to %s via %s",
  664.                stats( input ),
  665.                ruser,
  666.                remoteMail ? "@" : "",
  667.                remoteMail ? rnode : "",
  668.                address ,
  669.                path);
  670.  
  671. /*--------------------------------------------------------------------*/
  672. /*          Create the UNIX format of the file names we need          */
  673. /*--------------------------------------------------------------------*/
  674.  
  675.    if ((seqno == 0) ||
  676.        (SavePath == NULL) ||
  677.        !equal(SavePath, path) ||
  678.        ((int) (strlen(everyone) + strlen(address) + 2) > (int) sizeof everyone))
  679.    {
  680.       char *seq;
  681.       seqno = getseq();
  682.       seq = JobNumber( seqno );
  683.  
  684.       if  (SavePath != NULL )
  685.       {
  686.          free(SavePath);
  687.          SavePath = NULL;
  688.       } /* if */
  689.  
  690.       sprintf(tmfile, spool_fmt, 'C', path,     'C' , seq);
  691.       sprintf(idfile, dataf_fmt, 'D', E_nodename , seq, 'd');
  692.       sprintf(rdfile, dataf_fmt, 'D', E_nodename , seq, 'r');
  693.       sprintf(ixfile, dataf_fmt, 'D', E_nodename , seq, 'e');
  694.       sprintf(rxfile, dataf_fmt, 'X', E_nodename , seq, 'r');
  695.       strcpy(everyone,address);
  696.  
  697.    } /* if */
  698.    else {
  699.       strcat(everyone," ");
  700.       strcat(everyone,address);
  701.    } /* else */
  702.  
  703. /*--------------------------------------------------------------------*/
  704. /*                     create remote X (xqt) file                     */
  705. /*--------------------------------------------------------------------*/
  706.  
  707.    importpath( msname, ixfile, path);
  708.    mkfilename( msfile, E_spooldir, msname);
  709.  
  710.    stream = FOPEN(msfile, "w", BINARY_MODE);
  711.    if ( stream == NULL )
  712.    {
  713.       printerr(msfile);
  714.       printmsg(0, "DeliverRemote: cannot open X file %s", msfile);
  715.       return 0;
  716.    } /* if */
  717.  
  718.  
  719.    fprintf(stream, "R %s@%s\nU %s %s\nF %s\nI %s\nC rmail %s\n",
  720.                ruser, rnode, uuser , E_nodename,
  721.                rdfile, rdfile, everyone);
  722.    fclose(stream);
  723.  
  724.    if (SavePath != NULL)
  725.       return 1;
  726.  
  727. /*--------------------------------------------------------------------*/
  728. /*  Create the data file with the mail to send to the remote system   */
  729. /*--------------------------------------------------------------------*/
  730.  
  731.    importpath(msname, idfile, path);
  732.    mkfilename( msfile, E_spooldir, msname);
  733.  
  734.    stream = FOPEN(msfile, "w", BINARY_MODE);
  735.    if (stream == NULL )
  736.    {
  737.       printerr(msfile);
  738.       printmsg(0,
  739.                "DeliverRemote: Cannot open spool file \"%s\" for output",
  740.                 msfile);
  741.       return 0;
  742.    }
  743.  
  744.    if (!CopyData( TRUE, input , stream ))
  745.    {
  746.       remove( msfile );
  747.       return 0;
  748.    }
  749.  
  750. /*--------------------------------------------------------------------*/
  751. /*                     create local C (call) file                     */
  752. /*--------------------------------------------------------------------*/
  753.  
  754.    importpath( msname, tmfile, path);
  755.    mkfilename( msfile, E_spooldir, msname);
  756.  
  757.    stream = FOPEN(msfile, "w",TEXT_MODE);
  758.    if (stream == NULL)
  759.    {
  760.       printerr( msname );
  761.       printmsg(0, "DeliverRemote: cannot open C file %s", msfile);
  762.       return 0;
  763.    }
  764.  
  765.    fprintf(stream, send_cmd, idfile, rdfile, uuser, idfile);
  766.    fprintf(stream, send_cmd, ixfile, rxfile, uuser, ixfile);
  767.    fclose(stream);
  768.  
  769.    if (bflag[F_MULTI])        /* Deliver to multiple users at once?  */
  770.       SavePath = strdup(path);   /* Yes --> Save routing info        */
  771.  
  772.    return 1;
  773. } /* DeliverRemote */
  774.  
  775. /*--------------------------------------------------------------------*/
  776. /* C o p y D a t a                                                    */
  777. /*                                                                    */
  778. /* Copy data into its final resting spot                              */
  779. /*--------------------------------------------------------------------*/
  780.  
  781. static int CopyData( const boolean remotedelivery,
  782.                      const char *input,
  783.                      FILE *dataout)
  784. {
  785.    FILE *datain = FOPEN(input, "r",TEXT_MODE);
  786.    char buf[BUFSIZ];
  787.    int column = 0;
  788.    boolean success = TRUE;
  789.  
  790.    int (*put_string) (char *, FILE *) = (int (*)(char *, FILE *)) fputs;
  791.                               /* Assume no Kanji translation needed  */
  792.  
  793. /*--------------------------------------------------------------------*/
  794. /*                      Verify the input opened                       */
  795. /*--------------------------------------------------------------------*/
  796.  
  797.    if (datain == NULL)
  798.    {
  799.       printerr(input);
  800.       printmsg(0,"Unable to open input file \"%s\"", input);
  801.       fclose(dataout);
  802.       return 0;
  803.    } /* datain */
  804.  
  805. /*--------------------------------------------------------------------*/
  806. /*    When we do the From line, we also determine if we must          */
  807. /*    translate the data.  Note that the default is initialized to    */
  808. /*    fputs() above.                                                  */
  809. /*                                                                    */
  810. /*    If Kanji is not enabled, don't translate it                     */
  811. /*                                                                    */
  812. /*    If local mail queued for local delivery, the data is already    */
  813. /*    in Shift JIS, so don't translate it.                            */
  814. /*                                                                    */
  815. /*    If remote mail is queued for remote delivery, the data is       */
  816. /*    already in JIS 7bit, so don't translate it.                     */
  817. /*                                                                    */
  818. /*    If delivering remote mail locally, translate to Shift JIS       */
  819. /*                                                                    */
  820. /*    If delivering local mail remotely, translate to JIS 7 bit       */
  821. /*--------------------------------------------------------------------*/
  822.  
  823. /*--------------------------------------------------------------------*/
  824. /*                        Generate a FROM line                        */
  825. /*--------------------------------------------------------------------*/
  826.  
  827.    switch( (int) remoteMail * 2 + (int) remotedelivery )
  828.    {
  829.       case 3:                 /* Remote sender, remote delivery      */
  830.          strcpy( buf, fromuser );
  831.          strtok( buf, "!");   /* Get first host in list              */
  832.  
  833.          if ( equal(HostAlias( buf ), fromnode ))
  834.                               /* Host already in list?               */
  835.          {                    /* Yes --> Don't do it twice           */
  836.             fprintf(dataout, "From %s %s remote from %s\n",
  837.                      fromuser, now, E_nodename);
  838.             break;
  839.          }
  840.          else {                /* No --> Insert it                    */
  841.             fprintf(dataout, "From %s!%s %s remote from %s\n",
  842.                      fromnode, fromuser, now, E_nodename);
  843.             break;
  844.          }
  845.  
  846. /*--------------------------------------------------------------------*/
  847. /*    Note:  For the Kanji translation we re-check the                */
  848. /*    remoteDelivery flag since we do the fall through from above.    */
  849. /*--------------------------------------------------------------------*/
  850.  
  851.       case 2:                 /* Remote sender, local delivery       */
  852.          if ( bflag[ F_KANJI ] )
  853.                               /* Kanji from remote node?             */
  854.             put_string = (int (*)(char *, FILE *)) fputs_shiftjis;
  855.                               /* Yes --> Translate it                */
  856.  
  857.          fprintf(dataout, "From %s %s remote from %s\n",
  858.                   fromuser, now, fromnode);
  859.          break;
  860.  
  861.       case 1:                 /* Local sender, remote delivery       */
  862.          if ( bflag[F_KANJI]) /* Translation enabled?                */
  863.             put_string = (int (*)(char *, FILE *)) fputs_jis7bit;
  864.                               /* Translate into 7 bit Kanji          */
  865.  
  866.          column = strlen(E_domain) - 5;
  867.          if ((column > 0) && equali(&E_domain[column],".UUCP"))
  868.                               /* UUCP domain?                        */
  869.             fprintf(dataout, "From %s %s remote from %s\n",
  870.                              fromuser, now, E_nodename);
  871.                               /* Yes --> Use simple address          */
  872.          else
  873.             fprintf(dataout, "From %s!%s %s remote from %s\n",
  874.                   E_domain, fromuser, now, E_nodename);
  875.                               /* No --> Use domain address           */
  876.          break;
  877.  
  878.       case 0:                 /* Local sender, local delivery        */
  879.          fprintf(dataout, "From %s %s\n", fromuser, now);
  880.          break;
  881.  
  882.    } /* switch */
  883.  
  884. /*--------------------------------------------------------------------*/
  885. /*                       Loop to copy the data                        */
  886. /*--------------------------------------------------------------------*/
  887.  
  888.    while (fgets(buf, BUFSIZ, datain) != NULL)
  889.    {
  890.       if ((*put_string)(buf, dataout) == EOF)     /* I/O error? */
  891.       {
  892.          printerr("output");
  893.          printmsg(0,"I/O error on \"%s\"", "output");
  894.          fclose(dataout);
  895.          return 0;
  896.       } /* if */
  897.    } /* while */
  898.  
  899. /*--------------------------------------------------------------------*/
  900. /*                      Close up shop and return                      */
  901. /*--------------------------------------------------------------------*/
  902.  
  903.    if (ferror(datain))        /* Clean end of file on input?         */
  904.    {
  905.       printerr(input);
  906.       clearerr(datain);
  907.       success = FALSE;
  908.    }
  909.  
  910.    fclose(datain);
  911.    fclose(dataout);
  912.    return success;
  913.  
  914. } /* CopyData */
  915.  
  916. /*--------------------------------------------------------------------*/
  917. /*       b o u n c e                                                  */
  918. /*                                                                    */
  919. /*       Report failed mail to a user.  Based on code contributed     */
  920. /*       by Kevin Meyer <kmeyer@sauron.alt.za>                        */
  921. /*                                                                    */
  922. /*       This code has a major hole in that the address it replies    */
  923. /*       to is weak, really having been previously only been used     */
  924. /*       for internal messages.  Perhaps the full address from the    */
  925. /*       UUCP From line should be used.                               */
  926. /*--------------------------------------------------------------------*/
  927.  
  928. size_t Bounce( const char *input,
  929.                const char *text,
  930.                const char *data,
  931.                const char *address ,
  932.                const boolean validate )
  933. {
  934.    FILE *newfile, *otherfile;
  935.    char tname[FILENAME_MAX]; /* name of temporary file used */
  936.    char buf[BUFSIZ];
  937.    char sender[MAXADDR];
  938.  
  939.    boolean bounce = bflag[F_BOUNCE];
  940.  
  941.    sprintf(sender, "%s%s%s",
  942.                ruser,
  943.                remoteMail ? "@" : "",
  944.                remoteMail ? rnode : "" );
  945.  
  946.     printmsg(0,"Bounce: Mail from %s for %s failed, %s: %s",
  947.                sender,
  948.                address,
  949.                text,
  950.                (data == NULL) ? "(no data)" : data );
  951.  
  952. /*--------------------------------------------------------------------*/
  953. /*           Never bounce mail to a select list of user ids           */
  954. /*--------------------------------------------------------------------*/
  955.  
  956.    if ( equali( ruser, "postmaster") ||
  957.         equali( ruser, "uucp") ||
  958.         equali( ruser, "root") ||
  959.         equali( ruser, "mmdf") ||
  960.         equali( ruser, "mailer-daemon"))
  961.       bounce = FALSE;
  962.  
  963.    if ( ! bounce )
  964.      return Deliver( input, E_postmaster, FALSE, validate );
  965.  
  966.    mktempname( tname , "TMP");  // Generate a temp file name
  967.  
  968.    if ((otherfile = FOPEN(input,"r", TEXT_MODE ))==NULL)
  969.    {
  970.        printerr( input );
  971.        panic();
  972.    };
  973.  
  974.    if ((newfile = FOPEN(tname, "w", TEXT_MODE ))==NULL)
  975.    {
  976.        printerr( tname );
  977.        panic();
  978.    };
  979.  
  980.    fprintf(newfile,
  981.      "Dear %s,\n"
  982.      "Your message for address <%s> could not be delivered at system\n"
  983.      "%s (uucp node %s) for the following reason:\n\t\t%s.\n",
  984.                   ruser,
  985.                   address, E_domain, E_nodename, text );
  986.  
  987.    if ( data != NULL )
  988.       fprintf(newfile,
  989.              "The problem address or file in question was:  %s\n",
  990.              data );
  991.  
  992.       fprintf(newfile,
  993.               "\nA copy of the failed mail follows.\n\n"
  994.               "Electronically Yours,\n"
  995.               "%s %s UUCP mailer daemon\n",
  996.               compilep, compilev );
  997.  
  998.     fputs("\n------ Failed Message Follows -----\n", newfile);
  999.  
  1000.     while ( fgets(buf, sizeof buf, otherfile) != NULL)
  1001.       fputs(buf, newfile);
  1002.  
  1003.     fclose(newfile);
  1004.     fclose(otherfile);
  1005.  
  1006. /*--------------------------------------------------------------------*/
  1007. /*          Recursively invoke RMAIL to deliver our message           */
  1008. /*--------------------------------------------------------------------*/
  1009.  
  1010.    putenv("LOGNAME=uucp");
  1011.  
  1012.    sprintf( buf, "-w -F %s -s \"Failed mail for %.20s\" %s -c postmaster",
  1013.             tname,
  1014.             address,
  1015.             sender );
  1016.  
  1017.     if ( execute( myProgramName, buf, NULL, NULL, TRUE, FALSE ))
  1018.          DeliverLocal( input, E_postmaster, FALSE, validate);
  1019.  
  1020.     return (1);
  1021.  
  1022. } /* Bounce */
  1023.  
  1024.  
  1025. /*--------------------------------------------------------------------*/
  1026. /*    s t a t s                                                       */
  1027. /*                                                                    */
  1028. /*    Report size of file in message, if desired                      */
  1029. /*--------------------------------------------------------------------*/
  1030.  
  1031. static char *stats( const char *fname )
  1032. {
  1033.    if (bflag[ F_COLLECTSTATS ] )
  1034.    {
  1035.       long size;
  1036.       time_t ltime = stater(fname, &size);
  1037.  
  1038.       if ( ltime == -1 )
  1039.       {
  1040.          printerr( fname );
  1041.          return "(unknown size)";
  1042.       }
  1043.       else {
  1044.          static char buf[25];  /* "(nnnnnnn bytes) " */
  1045.                                /*  ....+....+....+.. */
  1046.          sprintf(buf,   "(%ld bytes) ",size );
  1047.          return buf;
  1048.       } /* else */
  1049.    } /* if */
  1050.    else
  1051.       return "";              /* Pretend we were never here       */
  1052.  
  1053. } /* stats */
  1054.